#coding: utf-8 

import pygame
import cPickle as pickle

from auxMath import frange

from position import *
from gameUtils import *
from matrix import *
from dirt import *

from doors import *
from room import *
from position import *
from matrix import *

from debugSprite import *
from visionSegmentation import *

from simData import *

from time import *

class Floor(pygame.sprite.Sprite):
	dirt=None
	walls=None
	rooms=[]
	corridors=[]
	obstacles=[]
	hidden_img=None
	
	def __init__(self,parent,floorName,scale):
		u"""Floor Class"""
		pygame.sprite.Sprite.__init__(self, self.containers) # Sprite inicialization
		self.parent=parent
		self.cleanSim=parent
		self.scale=scale
		self.name=floorName
		
		self.doors=[]
		self.rooms=[]
		
		self.surface=load_image(floorName+'.png',colorkey=(0,255,0))
		Xmax=self.surface.get_size()[0]
		self.dirt=Dirt(self,floorName,scale/Xmax)
		self.debug=DebugSprite(self,floorName,scale/Xmax)
		self.load(floorName)
		#self.save(floorName+'/'+floorName)
		self.loadSurfaces()
		self.loadRoomsGenetic()
		
		self.update(visible=True)
	
	def load(self,name=None):
		if name==None:
			name=self.name
		
		dirname=name+'/'
		try:
			self.walls = pickle.load(file(dirname+name+'_walls.pkl'))
			self.rooms = pickle.load(file(dirname+name+'_rooms.pkl'))
			self.doors = pickle.load(file(dirname+name+'_doors.pkl'))
			self.connections = pickle.load(file(dirname+name+'_connections.pkl'))
			
			
		except:
			print 'Unable to load floor "'+name+'"'
			print 'Going to rebuild it'
			self.save(name)
	
	def save(self,name=None):
		if name==None:
			name=self.name
		
		print "* Searching walls..."
		self.findWalls()
		print "* Searching rooms..."
		self.findRooms()
		print "* Searching doors..."
		self.findDoors()
		print "* Searching connections..."
		self.searchConnections()
		self.markConnectedDoors()
		self.markConnectedRooms()

		from os import mkdir
		try:
			mkdir(name)
		except:
			pass
		
		dirname=name+'/'
		pickle.dump(self.walls, file(dirname+name+'_walls.pkl', 'w'))
		pickle.dump(self.rooms, file(dirname+name+'_rooms.pkl', 'w'))
		pickle.dump(self.doors, file(dirname+name+'_doors.pkl', 'w'))
		pickle.dump(self.connections, file(dirname+name+'_connections.pkl', 'w'))
		
		print 'Saved in "'+name+'_*.pkl"'
	
	def saveGenes(self,name=None):
		if name == None:
			name=self.name
		
		genes={}
		for room in self.rooms:
			try:
				winner = room.winner
				if winner is not None:
					genes[room.name]=winner
			except:
				pass
		
		dirname=name+'/'
		pickle.dump(genes,file(dirname+name+'_room_genes.pkl','w'))
	def loadSurfaces(self):
		for door in self.doors:
			door.loadSprites(self)
		for room in self.rooms:
			room.loadSprites(self)
	
	def loadRoomsGenetic(self):
		for room in self.rooms:
			room.defineGeneticAlg(population=10,generations=10)
		
		name=self.name
		dirname=name+'/'
		try:
			genes = pickle.load(file(dirname+name+'_room_genes.pkl'))
			
			for room_name,room_winner in genes.items():
				for room in self.rooms:
					if room.name==room_name:
						room.win=room_winner
				
			
		except:
			from geneticRoom import *
			from copy import copy
			
			for room in self.rooms:
				try:
					areas=copy(room.areas)
					currentArea=0
					currentPos=areas[0].center
					order=[0]
					areas.pop(currentArea)
					
					while(len(areas)>0):
						nearest=None
						minDist='None'
						
						for key,area in areas.items():
							dist2Area=currentPos.dist_to(area.center)
							if minDist>dist2Area:
								minDist=dist2Area
								nearest=key
						
						order.append(nearest)
						currentArea=nearest
						currentPos=areas[nearest].center
						areas.pop(nearest)
					
					
					numSort=len(room.areas)
					sortGene=SortGene(state=order,numSort=numSort)
					areasGenes=[Gene() for gene in range(numSort*4)]
					chromosome = [sortGene]+areasGenes
					
					room.win = RoomIndividual(chromosome = chromosome , numSort = numSort)
				except:
					print "impossível fazer o load do",room.name

	def getLarguraPx(self):
		return self.surface.get_width()
	def getAlturaPx(self):
		return self.surface.get_height()
	def getAltura(self):
		return self.getAlturaPx()/self.scale
	def getLargura(self):
		return self.getLarguraPx()/self.scale
		
	def getPixelIn(self,pos):
		if isinstance(pos,Position):
			x=pos.x
			y=pos.y
		elif isinstance(pos,tuple):
			x=pos[0]
			y=pos[1]
			
		ymax=self.getAlturaPx()
		return (int(x*self.scale),int(ymax-y*self.scale))
		
	def getPixelInScreen(self,pos):
		if isinstance(pos,Position):
			x=pos.x
			y=pos.y
		elif isinstance(pos,tuple):
			x=pos[0]
			y=pos[1]
			
		ymax=self.getAltura()
		return (int(x*PIXEL2M*self.cleanSim.ZOOM),int((ymax-y)*PIXEL2M*self.cleanSim.ZOOM)) #PIXEL2M/self.cleanSim.ZOOM
		
		
	def getPositionIn(self,x,y):
		ymax=self.getAlturaPx()
		
		return Position(float(x)/self.scale,float(ymax-y)/self.scale)
	
	def getRoomBy(self,color):
		for room in self.rooms:
			if room.name==color:
				return room
				break
	
	def findWalls(self):
		pass

	def searchAround(self,search,mark,matrix,x,y):
		matrix.setitem(x,y,mark)
		for dx,dy in [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]:
			if matrix.getitem(x+dx,y+dy)==search:
				self.searchAround(search,mark,matrix,x+dx,y+dy)
				
	def findDoors(self):
		self.doors=[]
		xmax=self.getLarguraPx()
		ymax=self.getAlturaPx()
		
		aDoors=Area(1,0,0)

		search=-1
		nothing=False
		
		def format(f):
			return '%.2f' % f
		
		time0=time()
		print 'step 1/8',
		for x in range(xmax):
			for y in range(ymax):
				pixel =self.surface.get_at((x,y))[:3]
				if pixel == P_DOOR:
					aDoors.setitem(x,y,search)
		
		etiquetas=0
		etiquetagem=[]
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 2/8',
		for y in range(ymax):
			for x in range(xmax):
				if aDoors.getitem(x,y) == search:
					mark=[]
					if (aDoors.getitem(x-1,y) <> False):
						mark.append(aDoors.getitem(x-1,y))
					if (aDoors.getitem(x-1,y-1) <> False):
						mark.append(aDoors.getitem(x-1,y-1))
					if (aDoors.getitem(x,y-1) <> False):
						mark.append(aDoors.getitem(x,y-1))
					if (aDoors.getitem(x+1,y-1) <> False):
						mark.append(aDoors.getitem(x+1,y-1))
					if (len(mark)==0):
						etiquetas+=1
						mark.append(etiquetas)
					if (len(mark)>=1):
						mark.sort()
						etiquetagem.append(mark)
						
					aDoors.setitem(x,y,mark[0])
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 3/8',
		etiquetagem=unite(etiquetagem)
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 4/8',
		dEtiq={}
		for i in etiquetagem:
			dEtiq[len(dEtiq)+1]=i
		
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 5/8',
		
		invDictEtic={}
		for name,nums in dEtiq.items():
			for num in nums:
				invDictEtic[num]=name
		
		
		invDictEtic[nothing]=0
		
		
		for x in range(xmax):
			for y in range(ymax):
				num=aDoors.getitem(x,y)
				aDoors.setitem(x,y,invDictEtic[num])
						
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 6/8',
		
		for name,nums in dEtiq.items():
			self.doors.append(Door(name))
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 7/8',
		
		for x in range(xmax):
			for y in range(ymax):
				i=aDoors.getitem(x,y)
				if i!=0:
					i-=1
					self.doors[i].sum_x+=x
					self.doors[i].sum_y+=y
					self.doors[i].count_px+=1
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 8/8',
		
		for door in self.doors:
			door.pos=self.getPositionIn(door.sum_x/door.count_px,door.sum_y/door.count_px)
		
		print 'done in ' + format(time()-time0) + 's'

		self.aDoors=aDoors
	
	def findRooms(self):
		self.rooms=[]
		xmax=self.getLarguraPx()
		ymax=self.getAlturaPx()
		
		aRooms=Area(1,0,0)

		search=-1
		nothing=False
		
		time0=time()
		
		def format(f):
			return '%.2f' % f
		
		print 'step 1/7',
		for x in range(xmax):
			for y in range(ymax):
				pixel =self.surface.get_at((x,y))[:3]
				if pixel == P_ROOM:
					aRooms.setitem(x,y,search)
		
		etiquetas=0
		etiquetagem=[]
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 2/7',
		for y in range(ymax):
			for x in range(xmax):
				if aRooms.getitem(x,y) == search:
					mark=[]
					if (aRooms.getitem(x-1,y) <> False):
						mark.append(aRooms.getitem(x-1,y))
					if (aRooms.getitem(x-1,y-1) <> False):
						mark.append(aRooms.getitem(x-1,y-1))
					if (aRooms.getitem(x,y-1) <> False):
						mark.append(aRooms.getitem(x,y-1))
					if (aRooms.getitem(x+1,y-1) <> False):
						mark.append(aRooms.getitem(x+1,y-1))
					if (len(mark)==0):
						etiquetas+=1
						mark.append(etiquetas)
					if (len(mark)>=1):
						mark.sort()
						etiquetagem.append(mark)
						
					aRooms.setitem(x,y,mark[0])
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 3/7',
		etiquetagem=unite(etiquetagem)
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 4/7',
		dEtiq={}
		for i in etiquetagem:
			dEtiq[len(dEtiq)+1]=i
		
		
		invDictEtic={}
		for name,nums in dEtiq.items():
			for num in nums:
				invDictEtic[num]=name
		
		
		invDictEtic[nothing]=0
		
		
		for x in range(xmax):
			for y in range(ymax):
				num=aRooms.getitem(x,y)
				aRooms.setitem(x,y,invDictEtic[num])
						
		
		for name,nums in dEtiq.items():
			self.rooms.append(Room(name))
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 5/7',
		
		# encontrar os pontos a limpar em cada compartimento
		xMaxM=self.getLargura()
		yMaxM=self.getAltura()

		dirtMatMaxX=int(xMaxM/CLEANGRID)
		dirtMatMaxY=int(yMaxM/CLEANGRID)
		
		aDirt=Area(CLEANGRID,dirtMatMaxX,dirtMatMaxY)
		
		for x in range(dirtMatMaxX):
			for y in range(dirtMatMaxY):
				xInImage=int(x*CLEANGRID*self.scale)
				yInImage=int(y*CLEANGRID*self.scale)
				num=aRooms.getitem(xInImage,yInImage)
				aDirt.setitem(x,y,num)
				
				#if room_num !=-1:
				#	self.rooms[room_num].points.append((x,int(yMaxM/CLEANGRID)+1-y))
				
			#c.floor.debug.drawPositions(c.rooms[7].area.getPositions())
		pxBetweenCells=int(round(CLEANGRID*self.scale))
		
		for y in range(dirtMatMaxY):
			for x in range(1,dirtMatMaxX-1):
				room_num=aDirt.getitem(x,y)-1
				if (room_num!=-1):
					for dx in range(-pxBetweenCells/2,pxBetweenCells/2):
						item = aRooms.getitem(int(x*CLEANGRID*self.scale)+dx,int(y*CLEANGRID*self.scale))-1
						if (item ==-1):
							aDirt.setitem(x,y,0)
					for dy in range(-pxBetweenCells/2,pxBetweenCells/2):
						item = aRooms.getitem(int(x*CLEANGRID*self.scale),int(y*CLEANGRID*self.scale)+dy)-1
						if (item ==-1):
							aDirt.setitem(x,y,0)

		for y in range(dirtMatMaxY):
			for x in range(dirtMatMaxX-1):
				room_num=aDirt.getitem(x,y)-1
				if room_num !=-1:
					self.rooms[room_num].points.append((x,dirtMatMaxY+1-y))
		
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 6/7',
		
		for x in range(xmax):
			for y in range(ymax):
				i=aRooms.getitem(x,y)
				if i!=0:
					i-=1
					self.rooms[i].sum_x+=x
					self.rooms[i].sum_y+=y
					self.rooms[i].count_px+=1
					
		
		print 'done in ' + format(time()-time0) + 's'
		time0=time()
		print 'step 7/7',
		
		for room in self.rooms:
			room.pos=self.getPositionIn(room.sum_x/room.count_px,room.sum_y/room.count_px)
			room.defineArea()
		
		print 'done in ' + format(time()-time0) + 's'

		self.aRooms=aRooms
		
		
		
	def markConnectedDoors(self):
		nodes=[]
		for room_name,door_name in self.connections:
			door=self.doors[door_name]
			if not door in nodes:
				nodes.append(door)
		
		for door in self.doors:
			door.connected=(door in nodes)
			
		
	def markConnectedRooms(self):
		nodes=[]
		for room_name,door_name in self.connections:
			room=self.getRoomBy(room_name)
			if not room in nodes:
				nodes.append(room)
		
		for room in self.rooms:
			room.connected=(room in nodes)
			
		

	def searchConnections(self):
		connections=[]
		
		xmax=self.getLarguraPx()
		ymax=self.getAlturaPx()
		aLinkPoints=self.aDoors.getBorder()

		
		for x in range(1,xmax-1,1):
			for y in range(1,ymax-1,1):
				# se for a aborda de uma porta
				door=aLinkPoints.getitem(x,y)-1
				if door >= 0:
					for dx,dy in [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]:
						pixel=self.aRooms.getitem(x+dx,y+dy)
						if pixel != False:
							room='r'+str(pixel)
							connection=[room,door]
							if connection not in connections:
								connections.append(connection)
		self.connections=connections
		
				
		
	def update(self,visible):
		self.dirt.update(visible)
		self.debug.update(visible)
		for room in self.rooms:
			room.update(visible)
		
		for door in self.doors:
			door.update(visible)
			
		if visible:
			self.image=pygame.transform.smoothscale(self.surface, self.parent.screen.get_size())
		else:
			self.image=self.hidden_img
		
		self.rect = self.image.get_rect()

